#include "csv2sql.h"

namespace csv2sql
{
  // Scanner
  Scanner::Scanner(Options *o)
  {
    options = o;
    currentResult = 0;
  }
  Scanner::~Scanner()
  {
    if (currentResult)
      delete currentResult;
  }
  ScanResult *Scanner::Scan()
  {
    if (currentResult)
      delete currentResult;
    currentResult = new ScanResult(options);
    Parser p = Parser(options, currentResult);
    p.Parse();
    return currentResult;
  }

  // Scan Result (IWriter)
  ScanResult::ScanResult()
  {
    init();
  }
  ScanResult::ScanResult(Options *o)
  {
    init();
    options = o;
  }
  void ScanResult::init()
  {
    ColNames = 0;
    ColTypes = 0;
    ColSizes = 0;
    colIndex = 0;
    colNameIndex = 0;
  }
  
  ScanResult::~ScanResult()
  {
    if (ColNames)
      delete[] ColNames;
    if (ColTypes)
      delete[] ColTypes;
    if (ColSizes)
      delete[] ColSizes;
  }
      
  bool ScanResult::Write(int c, ParserMode m)
  {
    if (m & PM_HEAD)
      return (colNameData[colNameIndex++]=(char)c);
    colLength++;
    if (ColTypes[colIndex] < 2)
      return true;
    if ((c < '0' || c > '9') && c != '-')
    {
      ColTypes[colIndex] -= DT_INTEGER;
      if (c != '.' || decimalPos > 0)
        ColTypes[colIndex] -= DT_DECIMAL;
      else
        decimalPos = colLength;
      if (!strchr((char *)" :", c))
        ColTypes[colIndex] -= DT_DATE;
    }
    // printf("%c{%i:%i}",c,colIndex,ColTypes[colIndex]);
    return true;
  }

  bool ScanResult::Start()
  {
    return true;
  }
  bool ScanResult::StartCell(ParserMode m)
  {
    if (m & PM_HEAD)
      return (ColCount++);
    colLength = 0;
    decimalPos = 0;
    if (ColTypes[colIndex] == 0)
      ColTypes[colIndex] = DT_ANY;
    return true;
  }
  bool ScanResult::EndCell(ParserMode m)
  {
    if (m & PM_HEAD)
      if (colNameIndex > C2S_COLNAMEDATA_MAX)
        throw fprintf(stderr, C2S_COLNAMEDATA_ERR);
      else
        return (colNameData[colNameIndex++]=0);
    adjustColSize();
    colIndex++;
    return true;
  }
  
  bool ScanResult::StartRow(ParserMode m)
  {
    colIndex = 0;
    if (m & PM_HEAD)
      return (ColCount++);
    colLength = 0;
    decimalPos = 0;
    if (ColTypes[colIndex] == 0)
      ColTypes[colIndex] = DT_ANY;
    return true;
  }
  bool ScanResult::EndRow(ParserMode m)
  {
    if (m & PM_HEAD)
    {
      if (colNameIndex > C2S_COLNAMEDATA_MAX)
        throw fprintf(stderr, C2S_COLNAMEDATA_ERR);
      colNameData[colNameIndex++]=0;
      // FIXME: Segfault on exit unless arrays are padded with an extra element
      // (but only with an even number of columns) ...?
      ColTypes = new DataType[ColCount+1];
      ColNames = new char *[ColCount+1];
      ColSizes = new DataSize[ColCount+1];
      ColNames[0] = colNameData;
      int n = 0;
      for(int i = 0; i<colNameIndex; i++)
        if (colNameData[i] == 0)
          ColNames[++n] = colNameData+i+1;
    }
    adjustColSize();
    colIndex = 0;
    return true;
  }  
  bool ScanResult::End()
  { 
    for (int i = 0; i<ColCount; i++)
    {
      if (ColTypes[i] & DT_INTEGER)
        ColTypes[i] = DT_INTEGER;
      else if (ColTypes[i] & DT_DECIMAL)
        ColTypes[i] = DT_DECIMAL;
      else if (ColTypes[i] & DT_DATE)
        ColTypes[i] = DT_DATE;
      else
        ColTypes[i] = DT_STRING;
    }
    return true;
  }
  
  void ScanResult::adjustColSize()
  {
    if (colLength > ColSizes[colIndex].Left)
       ColSizes[colIndex].Left = colLength;
    if (decimalPos && ColSizes[colIndex].Right < colLength - decimalPos)
      ColSizes[colIndex].Right = colLength - decimalPos;
  }
      
}

